package business.global.pk.tdk;

import business.global.room.RoomRecordMgr;
import business.global.room.base.AbsRoomPos;
import business.global.room.base.AbsRoomPosMgr;
import business.global.room.pk.PockerRoom;
import business.global.shareroom.ShareRoomMgr;
import business.tdk.c2s.cclass.TDKRoomSetInfo;
import business.tdk.c2s.iclass.*;
import cenum.ChatType;
import cenum.ClassType;
import cenum.PrizeType;
import cenum.RoomTypeEnum;
import cenum.room.*;
import com.ddm.server.common.CommLogD;
import com.ddm.server.common.Config;
import com.ddm.server.websocket.def.ErrorCode;
import com.ddm.server.websocket.handler.requset.WebSocketRequest;
import com.google.gson.Gson;
import core.network.http.proto.SData_Result;
import jsproto.c2s.cclass.BaseSendMsg;
import jsproto.c2s.cclass.pk.PKRoom_RecordPosInfo;
import jsproto.c2s.cclass.room.BaseCreateRoom;
import jsproto.c2s.cclass.room.BaseRoomConfigure;
import jsproto.c2s.cclass.room.GetRoomInfo;
import jsproto.c2s.cclass.room.RoomPosInfo;
import jsproto.c2s.iclass.S_GetRoomInfo;
import jsproto.c2s.iclass.room.SBase_Dissolve;
import jsproto.c2s.iclass.room.SBase_PosLeave;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;
import java.util.List;

/**
 * 莆仙吹牛 房间逻辑
 *
 * @author Huaxing
 */

public class TDKRoom extends PockerRoom {
    public CTDK_CreateRoom cfg;// 开房配置
    /**
     * 玩过游戏的人数
     */
    private int playedCount;
    private Map<Long,Long> playedMap;
    public boolean isEnd = false;


    /**
     * 莆仙吹牛配置
     */
    private TDKConfigMgr configMgr = new TDKConfigMgr();

    protected TDKRoom(BaseRoomConfigure<CTDK_CreateRoom> baseRoomConfigure, String roomKey, long ownerID) {
        super(baseRoomConfigure, roomKey, ownerID);
        // 初始公共配置
        this.initShareBaseCreateRoom(CTDK_CreateRoom.class, baseRoomConfigure);
        this.cfg = (CTDK_CreateRoom) this.getBaseRoomConfigure().getBaseCreateRoom();
    }


    public TDKConfigMgr getConfigMgr() {
        return configMgr;
    }

    @Override
    public SData_Result startGame(long pid) {
        try {
            lock();
            /*
            if (this.getOwnerID() <= 0L) {
                // 没有房主
                return SData_Result.make(ErrorCode.NotAllow, "ownerID <= 0L");
            }
            if (this.getOwnerID() != pid) {
                // 操作玩家不是房主
                return SData_Result.make(ErrorCode.NotAllow, "ownerID:{%d},Pid:{%d}", this.getOwnerID(), pid);
            }
            */
            if(this.getRoomPosMgr().getPosByPid(pid)==null){
                // 没有房主
                return SData_Result.make(ErrorCode.NotAllow, "pid :"+pid +" not in room ");
            }
            if (!RoomState.Init.equals(this.getRoomState())) {
                // 房间不是初始状态
                return SData_Result.make(ErrorCode.NotAllow, "RoomState not Init {%s}", this.getRoomState().name());
            }
            if (!startGameOtherCondition(pid)) {
                // 有玩家没准备
                return SData_Result.make(ErrorCode.NotAllow, "startGame not isAllready");
            }
            // 通知新房间创建
            this.getRoomTyepImpl().createNewSetRoom();
            // 进入游戏阶段
            this.setRoomState(RoomState.Playing);
            // 游戏开始操作
            this.startGameBase();
            //共享更新
            if (Config.isShare()) {
                ShareRoomMgr.getInstance().addShareRoom(this);
            }
            return SData_Result.make(ErrorCode.Success);
        } finally {
            unlock();
        }
    }


    @Override
    public SData_Result playerReady(boolean isReady, long pid) {
        try {
            lock();
            AbsRoomPos roomPos = this.getRoomPosMgr().getPosByPid(pid);
            if (roomPos == null) {
                // 找不到指定的位置信息
                return SData_Result.make(ErrorCode.NotAllow, "not in pos");
            }
            if (!RoomState.Init.equals(this.getRoomState())) {
                // 房间不处于初始阶段
                return SData_Result.make(ErrorCode.NotAllow, "playerReady RoomState Init :{%s}", this.getRoomState());
            }
            roomPos.setReady(isReady);
            if(this.getRoomPosMgr().isAllReady()){
                atOnceSetStart();
            }
            return SData_Result.make(ErrorCode.Success);
        } finally {
            unlock();
        }
    }


    /**
     * 立即开始游戏
     */
    public void atOnceSetStart(){
        // 设置房间状态
        this.setRoomState(RoomState.Playing);
        // 通知新房间创建
        this.getRoomTyepImpl().createNewSetRoom();
        // 游戏开始操作
        this.startGameBase();
        //共享更新
        if (Config.isShare()) {
            ShareRoomMgr.getInstance().addShareRoom(this);
        }
    }

    /*
     * 加入房间的其他条件 条件不满足不进入
     * */
    @Override
    public boolean enterRoomOtherCondition(long pid) {
        //YSJVB 去掉不要
        /*
        if (Objects.isNull(this.cfg)) {
            return !(((CTDK_CreateRoom) this.getBaseRoomConfigure().getBaseCreateRoom()).isKeptOutAfterStartGame() && !RoomState.Init.equals(this.getRoomState()));
        }
        return !(this.getRoomCfg().isKeptOutAfterStartGame() && !RoomState.Init.equals(this.getRoomState()));
        */
        return true;
    }


    /*
     * 主动离开房间的其他条件 条件不满足不退出
     * */
    @Override
    public boolean exitRoomOtherCondition(long pid) {
        // 玩家玩过游戏就不能离开
        TDKRoomPos pos = (TDKRoomPos) this.getRoomPosMgr().getPosByPid(pid);
        return !(Objects.nonNull(pos) && pos.isPlayTheGame());
    }

    /**
     * 主动开始房间的其他条件 条件不满足不开始
     *
     * @param pid
     * @return
     */
    @Override
    public boolean startGameOtherCondition(long pid) {
        // 如果人数 >= 7 ? 2-7人，可以中途加入:人满开始
        //YSJVB 去掉
        //return this.getPlayerNum() >= 7 || this.getPlayerNum() >= 6 ? this.startGameOther():this.getRoomPosMgr().isAllReady();

        //YSJVB  只要有2人准备就开始
        return this.startGameOther();
    }

    /*
     * 开始游戏的其他条件 条件不满足不进入
     * */
    public boolean startGameOther() {
        return this.getRoomPosMgr().getPosList().stream().filter(k -> k.getPid() > 0 && k.isReady()).count() >= 2L;
    }

    /**
     * 自动开始游戏 所有玩家准备好自动开始。
     */
    @Override
    public boolean autoStartGame() {
        if (RoomTypeEnum.NORMAL.equals(this.getRoomTypeEnum())) {
            return this.getPlayerNum() < 6;
        }
        return true;
    }


    public int getKillPlayerCount(){
        if (CollectionUtils.isEmpty(this.getRoomPosMgr().getPosList())) {
            // 玩家信息列表没数据
            return 0;
        }
        boolean isClubOrUnion = RoomTypeEnum.checkUnionOrClub(this.getRoomTypeEnum());
        List<Long> kickOutList = new ArrayList<>();
        if(isClubOrUnion){
            this.getRoomPosMgr().getPosList().stream().forEach(k -> {
                if ( k.getPid() <= 0L) {
                    return;
                }
                if( k.isLeaveNextSet()){
                    kickOutList.add(k.getPid());
                }
            });
        }
        return kickOutList.size();
    }

    /**
     * 踢出盟主标记的玩家
     *
     * @return
     */
    public void killPlayerByMengZhuMark() {
        if (CollectionUtils.isEmpty(this.getRoomPosMgr().getPosList())) {
            // 玩家信息列表没数据
            return;
        }
        boolean isClubOrUnion = RoomTypeEnum.checkUnionOrClub(this.getRoomTypeEnum());
        if(isClubOrUnion){
            List<Long> kickOutList = new ArrayList<>();
            this.getRoomPosMgr().getPosList().stream().forEach(k -> {
                if ( k.getPid() <= 0L) {
                    return;
                }
                if( k.isLeaveNextSet()){
                    kickOutList.add(k.getPid());
                }
            });
            //踢出房间
            kickOutList.stream().forEach(pid -> {
                AbsRoomPos roomPos = this.getRoomPosMgr().getPosByPid(pid);
                roomPos.insertPlayerRoomAloneBO();
                roomPos.updatePlayerRoomAloneBO();
                roomPos.leave(true, this.getOwnerID(), CKickOutType.TIMEOUT);
                this.getRoomPosMgr().setAllEnterTime(0);
            });

            ((TDKRoomSet)this.getCurSet()).kickOut(kickOutList);
        }
    }

    /**
     * 限时操作
     *
     * @return
     */
    public int getXianShi() {
        return this.getRoomCfg().getXianShi();
    }

    public int getPaiShu() {
        return this.getRoomCfg().getPaishu();
    }

    /**
     * 可选玩法
     *
     * @param kexuan
     * @return
     */
    public boolean keXuanWanFa(TDKdefine.TDK_KEXUAN kexuan) {
        return this.getRoomCfg().getKexuanwanfa().contains(kexuan.ordinal());
    }

    /**
     * 新一局
     */
    @Override
    public void startNewSet() {
        this.setCurSetID(this.getCurSetID() + 1);
        // / 计算庄位
        if (this.getCurSetID() == 1) {
            setDPos(((TDKRoomPosMgr) this.getRoomPosMgr()).randomPos());
        } else if (this.getCurSet() != null) {
            TDKRoomSet mRoomSet = (TDKRoomSet) this.getCurSet();
            // 根据上一局计算下一局庄家
            setDPos(mRoomSet.calcNextDPos());
            mRoomSet.clear();
        }
        // 每个位置，清空准备状态
        this.getRoomPosMgr().clearGameReady();
        // 通知局数变化
        this.getRoomTyepImpl().roomSetIDChange();
        this.setCurSet(new TDKRoomSet(this.getCurSetID(), this, this.getDPos()));
    }


    /**
     * 打牌操作
     *
     * @param request
     * @param pid        用户ID
     * @param setID      局数
     * @param roundID    回合
     * @param opType     打牌类型
     * @param opCardType 牌
     */
    public void opCard(WebSocketRequest request, long pid, int setID, int roundID, TDKdefine.TDK_OP opType, int opCardType) {
        try {
            lock();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            TDKRoomSet mCurSet = (TDKRoomSet) this.getCurSet();
            if (null == getCurSet() || getCurSet().getSetID() != setID) {
                request.error(ErrorCode.NotAllow, "not current setID:" + (getCurSet() != null ? getCurSet().getSetID() : 0));
                return;
            }
            if (mCurSet.getCurRound() == null || mCurSet.getCurRound().getRoundID() != roundID) {
                request.error(ErrorCode.NotAllow, "not current roundID:"
                        + (mCurSet.getCurRound() != null ? mCurSet.getCurRound().getRoundID() : 0));
                return;
            }
            AbsRoomPos pos = this.getRoomPosMgr().getPosByPid(pid);
            if (null == pos) {
                request.error(ErrorCode.NotAllow, "not find your pos:");
                return;
            }
            // 重置时间
            pos.setLatelyOutCardTime(0);
            mCurSet.getCurRound().opCard(request, pos.getPosID(), opType, opCardType);
        } catch (Exception e) {
            CommLogD.error(e.getMessage());
        } finally {
            unlock();
        }
    }

    /**
     * 操作看牌
     *
     * @param request
     * @param pos     位置
     */
    public void opKan(WebSocketRequest request, long pid, int pos) {
        try {
            lock();
            TDKRoomSet mCurSet = (TDKRoomSet) this.getCurSet();
            if (null == mCurSet) {
                request.error(ErrorCode.NotAllow, "not current");
                return;
            }
            if (SetState.End.equals(mCurSet.getState())) {
                request.error(ErrorCode.NotAllow, "not current End");
                return;
            }

            mCurSet.on_kan(request, pid, pos);
        } catch (Exception e) {
            CommLogD.error(e.getMessage());
        } finally {
            unlock();
        }
    }


    @Override
    public void RobotDeal(int pos) {
        if (this.getCurSet() != null) {
            TDKRoomSet mSetRoom = (TDKRoomSet) this.getCurSet();
            if (null != mSetRoom.getCurRound()) {
                mSetRoom.getCurRound().RobothandCrad(pos);
            }
        }
    }

    @Override
    public void cancelTrusteeship(AbsRoomPos pos) {
    }

    @Override
    public void roomTrusteeship(int pos) {
        if (this.getCurSet() != null) {
            TDKRoomSet mSetRoom = (TDKRoomSet) this.getCurSet();
            if (null != mSetRoom.getCurRound()) {
                mSetRoom.getCurRound().trusteeshipRoomPos(pos);
            }
        }
    }

    @Override
    public boolean isCanChangePlayerNum() {
        return true;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getCfg() {
        return (T) getRoomCfg();
    }

    @SuppressWarnings("rawtypes")
    @Override
    public GetRoomInfo getRoomInfo(long pid) {
        S_GetRoomInfo ret = new S_GetRoomInfo();
        // 设置房间公共信息
        this.getBaseRoomInfo(ret);
        if (null != this.getCurSet()) {
            ret.setSet(this.getCurSet().getNotify_set(pid));
        } else {
            ret.setSet(new TDKRoomSetInfo());
        }
        return ret;
    }

    @Override
    public void setEndRoom() {
        if (null != this.getCurSet()) {
            // 增加房局记录
            RoomRecordMgr.getInstance().add(this);
            ((TDKRoomSet) this.getCurSet()).getRoomPlayBack().playBack2All(STDK_RoomEnd.make(getAllShortPlayer().values(), getRoomEndResult()));
            refererReceiveList();
        }
    }


    @Override
    public BaseSendMsg ChangePlayerNum(long roomID, int createPos, int endSec, int playerNum) {
        return STDK_ChangePlayerNum.make(roomID, createPos, endSec, playerNum);
    }

    @Override
    public BaseSendMsg ChangePlayerNumAgree(long roomID, int pos, boolean agreeChange) {
        return STDK_ChangePlayerNumAgree.make(roomID, pos, agreeChange);
    }

    @Override
    public BaseSendMsg ChangeRoomNum(long roomID, String roomKey, int createType) {
        return STDK_ChangeRoomNum.make(roomID, roomKey, createType);
    }


    /**
     * 托管时间值
     *
     * @return
     */
    @Override
    public int trusteeshipTimeValue() {
        return  TDKdefine.TDK_XIANSHI_TYPE.valueOf(this.getRoomCfg().getXianShi()).value()*1000;
    }

    @Override
    public int getTimerTime() {
        return 500;
    }

    @Override
    public int getPlayingCount() {
        return (int) this.getRoomPosMgr().getPosList().stream().filter(x -> x.getPid() > 0 && x.isPlayTheGame()).count();
    }

    public synchronized void addPlayedMap(AbsRoomPos roomPos) {
        playedMap.put(roomPos.getPid(), roomPos.getClubID());
    }

    @Override
    public BaseSendMsg Trusteeship(long roomID, long pid, int pos, boolean trusteeship) {
        return STDK_Trusteeship.make(roomID, pid, pos, trusteeship);
    }

    @Override
    public BaseSendMsg PosLeave(SBase_PosLeave posLeave) {
        return STDK_PosLeave.make(posLeave);
    }

    @Override
    public BaseSendMsg LostConnect(long roomID, long pid, boolean isLostConnect, boolean isShowLeave) {
        return STDK_LostConnect.make(roomID, pid, isLostConnect, isShowLeave);
    }

    @Override
    public BaseSendMsg PosContinueGame(long roomID, int pos) {
        return STDK_PosContinueGame.make(roomID, pos);
    }

    @Override
    public BaseSendMsg PosUpdate(long roomID, int pos, RoomPosInfo posInfo, int custom) {
        return STDK_PosUpdate.make(roomID, pos, posInfo, custom);
    }

    @Override
    public BaseSendMsg PosUpdate(long roomID, int pos, RoomPosInfo posInfo, int visit, RoomPosInfo visitInfo, int custom) {
        return STDK_PosUpdate.make(roomID, pos, posInfo, visit, visitInfo, custom);
    }

    @Override
    public BaseSendMsg VisitUpdate(long roomID, int action, int pos, RoomPosInfo posInfo, int visit, RoomPosInfo visitInfo) {
        return STDK_VisitUpdate.make(roomID, action, pos, posInfo, visit, visitInfo);
    }

    @Override
    public BaseSendMsg PosReadyChg(long roomID, int pos, boolean isReady) {
        return STDK_PosReadyChg.make(roomID, pos, isReady);
    }

    @Override
    public BaseSendMsg Dissolve(SBase_Dissolve dissolve) {
        return STDK_Dissolve.make(dissolve);
    }

    @Override
    public BaseSendMsg StartVoteDissolve(long roomID, int createPos, int endSec) {
        return STDK_StartVoteDissolve.make(roomID, createPos, endSec);
    }

    @Override
    public BaseSendMsg PosDealVote(long roomID, int pos, boolean agreeDissolve, int endSec) {
        return STDK_PosDealVote.make(roomID, pos, agreeDissolve);
    }

    @Override
    public BaseSendMsg Voice(long roomID, int pos, String url) {
        return STDK_Voice.make(roomID, pos, url);
    }

    @Override
    public BaseSendMsg XiPai(long roomID, long pid, ClassType cType) {
        return STDK_XiPai.make(roomID, pid, cType);
    }

    @Override
    public BaseSendMsg ChatMessage(long pid, String name, String content, ChatType type, long toCId, int quickID) {
        return STDK_ChatMessage.make(pid, name, content, type, toCId, quickID);
    }

    @Override
    public <T> BaseSendMsg RoomRecord(List<T> records) {
        return STDK_RoomRecord.make(records);
    }

    @Override
    public String dataJsonCfg() {
        return new Gson().toJson(this.getRoomCfg());
    }

    @Override
    public AbsRoomPosMgr initRoomPosMgr() {
        return new TDKRoomPosMgr(this);
    }


    @Override
    public void initCreatePos() {
        if (this.getOwnerID() <= 0L) {
            return;
        }
        // 以观战身份进入房间，本来是以玩家
        this.enterRoomVisitor(this.getOwnerID(), AbsRoomPosMgr.visitIndex, false, null);
        this.getRoomPosMgr().getVisitByPid(this.getOwnerID()).setReady(!ownerNeedReady());
    }

    /**
     * 获取房间配置
     *
     * @return
     */
    public CTDK_CreateRoom getRoomCfg() {
        if (this.cfg == null) {
            // 初始公共配置
            this.initShareBaseCreateRoom(CTDK_CreateRoom.class, getBaseRoomConfigure());
            return (CTDK_CreateRoom) getBaseRoomConfigure().getBaseCreateRoom();
        }
        return this.cfg;
    }

    /**
     * 清除记录。
     */
    @Override
    public void clearEndRoom() {
        super.clear();
        cfg = null;// 开房配置
    }


    /**
     * 神牌消息 panvc
     *
     * @param msg
     * @param pid
     */
    @Override
    public boolean godCardMsg(String msg, long pid) {
        /*
        if (null == this.getCurSet()) {
            return false;
        }
        AbsMJSetRoom setRoom = (AbsMJSetRoom) this.getCurSet();
        return setRoom.getGodInfo().addGodCardMap(pid, msg);*/
        if (Objects.nonNull(this.getCurSet())) {
            return ((TDKRoomSet) this.getCurSet()).addGodCardMap(pid,msg);
        }
        return false;
    }

    @Override
    protected List<PKRoom_RecordPosInfo> getRecordPosInfoList() {
        return null;
    }


    /**
     * 自动准备游戏 玩家加入房间时，自动进行准备。
     */
    @Override
    public boolean autoReadyGame() {
        if (RoomTypeEnum.NORMAL.equals(this.getRoomTypeEnum())) {
            return true;
        }
        return this.getPlayerNum() < 6;
    }

    /**
     * 检查自动解散房间
     * @return
     */
    @Override
    public boolean checkAutoPullUp() {
        return false;
    }

    /**
     * 是否禁止语音
     *
     * @return
     */
    @Override
    public boolean isDisAbleVoice() {
        return checkGaoJiXuanXiang(GaoJiTypeEnum.DISABLE_VOICE);
    }

    public int getDiFen() {
        return this.getRoomCfg().getDifen();
    }
    public int getShangFenTime() {
        return  TDKdefine.TDK_SHANGFEN_TIME.valueOf(this.getRoomCfg().getSfsj()).value();
    }

    public int getXianShiSecond() {
        return  TDKdefine.TDK_XIANSHI_TYPE.valueOf(this.getRoomCfg().getXianShi()).value();
    }

    @Override
    public int getEmptyPosCount() {
        return super.getEmptyPosCount();
    }

    @Override
    public int getAllEmptyCount() {
        return super.getAllEmptyCount();
    }

    @Override
    public boolean checkExistAllEmpty() {
        return false;
    }

    @Override
    public boolean isNoneRoom() {
        return super.isNoneRoom();
    }

    //YSJVB 计算喜分
    /**
     * 抽喜分给盟主
     */
    public void updateClubCreaterXiFen(int xiFen) {
        if (PrizeType.Gold.equals(this.getBaseRoomConfigure().getPrizeType()) || this.getGameRoomBO().getRoomState() == RoomState.Init.value()) {
            this.deleteRecordRelated();
            return;
        }
        // 房间配置
        BaseCreateRoom baseCreateRoom = this.getBaseRoomConfigure().getBaseCreateRoom();
        // 竞技点收益分成点
        ((TDKRoomPosMgr)this.getRoomPosMgr()).calcXiFen(xiFen, baseCreateRoom, String.valueOf(this.getGameRoomBO().getDateTime()), this.getGameRoomBO().getDataJsonCfg(), this.getGameRoomBO().getConsumeValue(), this.getHistorySetSize(), getGameRoomBO().getGameType());

    }
}
